#pragma once
#include<vector>
#include<unordered_map>
#include<QMutex>
#include"MemUtil.h"
#include"Block.h"
#include"BlockDel.h"
#include"SkipListIndex.h"
#include"BitMap.h"
#include"TableInfo.h"
using namespace std;

class IncreWriteUtil{
public:
    static void increWriteAccrodUpDateInfo(unordered_map<ResourceInfo, vector<Record*>, ResInfoHash>& upDateInfo){
        for(const auto& pair : upDateInfo){
            const ResourceInfo& resInfo = pair.first;
            const DISKTYPE& diskType = resInfo.getDiskType();
            if(diskType == BLOCK){
                Block::increWriteToDisk(resInfo, pair.second);
            }
            else if(diskType == BLOCKDEL){
                BlockDel::increWriteToDisk(resInfo, pair.second);
            }
            else{
                throw string("diskType error");
            }
        }
        upDateInfo.clear();
    }

    static void optimizRecordStore(unordered_map<ResourceInfo, vector<Record*>, ResInfoHash>& dataRecordStore){
        for(auto& it : dataRecordStore){
            if(it.first.getDiskType() == BLOCK){//BlockDel无需化简
                it.second = Record::getOptimizRecordVec(it.second, true);   //优化的记录都是同一个资源的
            }
        }
    }


    static void increWriteAccrodIndexUpDateInfo(unordered_map<ResourceInfo, vector<IndexRecord*>, ResInfoHash>& indUpDateInfo, const bool& checkIsBeenWriten = false){
        for(const auto& iter : indUpDateInfo){
            SkipListIndex::increWriteToDisk(iter.first, iter.second, checkIsBeenWriten);
        }
        indUpDateInfo.clear();
    }

    static void optimizIndexRecordStore(unordered_map<ResourceInfo, vector<IndexRecord*>, ResInfoHash>& indRecordStore){
        for(auto& it : indRecordStore){
            it.second = IndexRecordUtil::getOptimizIndexRecordVec(it.second, false);    //未排好序
        }
    }

    static void increWriteAccrodBitMapUpDateInfo(unordered_map<ResourceInfo, vector<uint64_t>, ResInfoHash>& bitMapRecordStore){
        for(const auto& it : bitMapRecordStore){
            BitMap::increWriteToDisk(it.first, it.second);
        }
        bitMapRecordStore.clear();
    }
};


class MemRecordStore{
private:

    unordered_map<ResourceInfo, vector<Record*>, ResInfoHash> dataRecords;

    unordered_map<ResourceInfo, vector<IndexRecord*>, ResInfoHash> indOpRecords;

    unordered_map<ResourceInfo, vector<uint64_t>, ResInfoHash> bitMapRecords;

    int32_t dataRecCount = 0;

    QReadWriteLock recLock;

    //添加一个事务对所有数据文件的更改
    int32_t addRecords(const vector<pair<ResourceInfo, vector<Record*>>>& upDateInfo){
        int32_t recCount = 0;
        for(const auto& it : upDateInfo){
            const ResourceInfo& resInfo = it.first;
            const vector<Record*>& tmpRecords = it.second;
            recCount += tmpRecords.size();
            const DISKTYPE& diskType = resInfo.getDiskType();
            if(diskType == BLOCK || diskType == BLOCKDEL){
                vector<Record*>& resAddModRecords = dataRecords[resInfo];
                resAddModRecords.insert(resAddModRecords.end(), tmpRecords.begin(), tmpRecords.end());
            }
            else{
                throw string("diskType error");
            }
        }
        return recCount;
    }

    //添加一个事务对所有索引文件的更改
    int32_t addIndexRecords(const vector<pair<ResourceInfo, vector<IndexRecord*>>>& indexUpDateInfo){
        int32_t indRecCount = 0;
        for(const auto& it : indexUpDateInfo){
            const ResourceInfo& resInfo = it.first;
            const vector<IndexRecord*>& tmpIndexRecords = it.second;
            indRecCount += tmpIndexRecords.size();
            vector<IndexRecord*>& resOpRecords = indOpRecords[resInfo];
            resOpRecords.insert(resOpRecords.end(), tmpIndexRecords.begin(), tmpIndexRecords.end());
        }
        return indRecCount;
    }

    int32_t addBitMapRecords(const vector<pair<ResourceInfo, vector<uint64_t>>>& bitMapUpDateInfo){
        int32_t bitMapRecCount = 0;
        for(const auto& it : bitMapUpDateInfo){
            const ResourceInfo& resInfo = it.first;
            const vector<uint64_t>& tmpBitMapRecords = it.second;
            bitMapRecCount += tmpBitMapRecords.size();
            vector<uint64_t>& resOpRecords = bitMapRecords[resInfo];
            resOpRecords.insert(resOpRecords.end(), tmpBitMapRecords.begin(), tmpBitMapRecords.end());
        }
        return bitMapRecCount;
    }

public:

    void monoRecLock(){
        recLock.lockForWrite();
    }

    void releaseRecLock(){
        recLock.unlock();
    }

    int32_t addComitInfo(const vector<pair<ResourceInfo, vector<Record*>>>& upDateInfo, const vector<pair<ResourceInfo, vector<IndexRecord*>>>& indexUpDateInfo, const vector<pair<ResourceInfo, vector<uint64_t>>>& bitMapUpDateInfo){
        recLock.lockForWrite();
        const int32_t& tmpDataRecCount = addRecords(upDateInfo);   //以数据文件记录个数为准
        addIndexRecords(indexUpDateInfo);
        addBitMapRecords(bitMapUpDateInfo);
        this->dataRecCount += tmpDataRecCount;
        recLock.unlock();
        return tmpDataRecCount;
    }


    int32_t increWriteToDisk(){
        recLock.lockForWrite();
        int32_t writeRecordCount = this->dataRecCount;   //个数以每个事务的事务范围内化简后的个数相加为准（依据磁盘）
        this->dataRecCount = 0;
        if(writeRecordCount != 0){
            IncreWriteUtil::optimizRecordStore(dataRecords);
            IncreWriteUtil::optimizIndexRecordStore(indOpRecords);

            IncreWriteUtil::increWriteAccrodUpDateInfo(dataRecords);
            IncreWriteUtil::increWriteAccrodIndexUpDateInfo(indOpRecords);

            IncreWriteUtil::increWriteAccrodBitMapUpDateInfo(bitMapRecords);
        }
        recLock.unlock();
        return writeRecordCount;
    }


    bool isResUnIncreWriteToDisk(const ResourceInfo& resInfo){
        bool retVal;
        const DISKTYPE& diskType = resInfo.getDiskType();
        recLock.lockForRead();
        if(diskType == BLOCK || diskType == BLOCKDEL){
            retVal = dataRecords.find(resInfo) != dataRecords.end();
        }
        else if(diskType == SLINDEX){
            retVal = indOpRecords.find(resInfo) != indOpRecords.end();
        }
        else if(diskType == BITMAP){
            retVal = bitMapRecords.find(resInfo) != bitMapRecords.end();
        }
        else{
            throw string("diskType error");
        }
        recLock.unlock();
        return retVal;
    }
};
